package com.yunji.cabinet.business;

import com.google.common.collect.Maps;
import com.yunji.base.cache.BaseCache;
import com.yunji.base.domain.BelongDO;
import com.yunji.base.dto.AgentDTO;
import com.yunji.base.event.GuavaEventBus;
import com.yunji.cabinet.bo.*;
import com.yunji.cabinet.cache.CabinetCache;
import com.yunji.cabinet.consumer.CabinetConsumer;
import com.yunji.cabinet.context.calculate.CabinetCalculate;
import com.yunji.cabinet.context.convert.CabinetConvert;
import com.yunji.cabinet.context.validate.CapacityValidate;
import com.yunji.cabinet.device.ContainerTypeEnum;
import com.yunji.cabinet.device.DeviceCommandEngine;
import com.yunji.cabinet.device.DeviceSpinService;
import com.yunji.cabinet.device.factory.DeviceStrategyFactory;
import com.yunji.cabinet.domain.CabinetSiteDO;
import com.yunji.cabinet.domain.ContainerCell;
import com.yunji.cabinet.domain.ContainerDO;
import com.yunji.cabinet.domain.ContainerScanDO;
import com.yunji.cabinet.dto.*;
import com.yunji.cabinet.dto.device.CabinetCargoInfoDTO;
import com.yunji.cabinet.enums.CabinetScanActionEnums;
import com.yunji.cabinet.enums.CellStatus;
import com.yunji.cabinet.enums.LackStatus;
import com.yunji.cabinet.enums.UseStatus;
import com.yunji.cabinet.params.SpecificUpgradeCabinetParam;
import com.yunji.cabinet.service.ICabinetCellService;
import com.yunji.cabinet.service.ICabinetService;
import com.yunji.cabinet.service.ICabinetSiteService;
import com.yunji.cabinet.service.ICabinetTemplateService;
import com.yunji.cabinet.service.impl.ContainerCycleService;
import com.yunji.cabinet.service.impl.DeviceService;
import com.yunji.cabinet.service.impl.FillCargoInfoService;
import com.yunji.cabinet.service.impl.MaintainService;
import com.yunji.cabinet.vo.CabinetCycleVO;
import com.yunji.cabinet.vo.ContainerProductDetailVO;
import com.yunji.cabinet.vo.ContainerProductVO;
import com.yunji.cabinet.vo.SpecificUpgradeCabinetVO;
import com.yunji.common.base.BaseBusiness;
import com.yunji.common.cache.LockUtil;
import com.yunji.common.constant.LockCacheConstant;
import com.yunji.common.constant.LogicCode;
import com.yunji.common.enums.business.CapacityOperateEnum;
import com.yunji.common.enums.common.ErrorEnum;
import com.yunji.common.enums.common.UserType;
import com.yunji.common.event.SpringEventBus;
import com.yunji.common.event.entity.EventData;
import com.yunji.common.event.notice.LackCargoNoticeEvent;
import com.yunji.common.event.notice.NoCargoNoticeEvent;
import com.yunji.common.model.cache.CabinetCacheDTO;
import com.yunji.common.model.cache.ContainerTypeCacheDTO;
import com.yunji.common.model.domain.SiteDO;
import com.yunji.common.model.dto.LoginInfo;
import com.yunji.common.utils.ConvertDataUtil;
import com.yunji.common.utils.DecimalUtils;
import com.yunji.common.utils.RandomUtils;
import com.yunji.common.utils.TimeUtils;
import com.yunji.common.utils.bean.BeanUtils;
import com.yunji.coffee.entity.bo.CommonDeviceInfoBO;
import com.yunji.coffee.entity.dto.DeviceCellDetailDTO;
import com.yunji.coffee.entity.dto.ICommonDeviceDetail;
import com.yunji.coffee.entity.dto.ICommonDeviceInfo;
import com.yunji.order.domain.OrderDO;
import com.yunji.product.bo.ProductAgentSelectQueryBO;
import com.yunji.product.domain.ProductAgentDO;
import com.yunji.product.service.IProductAgentService;
import com.yunji.storage.domain.StockDO;
import com.yunji.storage.dto.StorageFiledDTO;
import com.yunji.storage.dto.StorageProductDTO;
import com.yunji.storage.event.StorageQuantityEvent;
import com.yunji.system.context.SystemContext;
import com.yunji.system.service.TokenService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Package com.yunji.web.business
 * FileName:	CabinetBusiness.java
 * Copyright:	Copyright © 2024 云集互联 All Rights Reserved
 * Company: 	云集互联
 * @version: 1.0
 * @since: JDK 1.8.0_202
 * Create at:	2024-04-08 19:50:14
 * Description:
 * 货柜业务处理
 * Modification History:
 * Author					Date						Version			Description
 * --------------------------------------------------------------------------------
 * HuaAo				2024-04-08 19:50:14			1.0				1.0 Version
 */
@Component
public class CabinetBusiness extends BaseBusiness {

    @Resource
    ICabinetService cabinetService;

    @Resource
    ICabinetSiteService cabinetSiteService;

    @Resource
    ICabinetCellService cellService;

    @Resource
    ICabinetTemplateService templateService;

    @Resource
    IProductAgentService productAgentService;

    @Resource
    CabinetConsumer cabinetConsumer;

    @Resource
    TokenService tokenService;

    @Resource
    private ContainerCycleService containerCycleService;

    @Resource
    private DeviceService deviceService;

    @Resource
    private MaintainService maintainService;

    @Resource
    private FillCargoInfoService fillCargoInfoService;


    public void handleParam(StorageFiledDTO param) {
        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        String userType = user.getUserType();
        String userText = UserType.getText(userType);
        param.setBindSearch(LogicCode.NO);
        logs.info("【货柜参数】当前用户所属ID:{}, 用户类型={}:{}", belongId, userType, userText);
        if (UserType.AGENT.getCode().equals(userType)) {
            param.setParentId(belongId);
        }
        if (UserType.SITE.getCode().equals(userType)) {
            param.setBelongId(belongId);
        }
    }

    /**
     * @Title preHandleCabinet
     * @Desc 预处理货柜信息
     * @Date 2024-04-10 10:22:54
     * @Param container 货柜信息
     */
    private void preHandleCabinet(CabinetDTO cabinet) {
        ContainerTypeCacheDTO containerType = CabinetCache.getContainerType(cabinet.getTypeCode());
        String chip = cabinet.getChipImei();
        Assert.isTrue((BeanUtils.isNotNull(chip)), "请上送芯片序列号");
        Assert.isTrue((BeanUtils.isNotNull(containerType)), "请上送货柜类型信息");

        List<ContainerCell> cells = cabinet.getCells();
        Assert.isTrue(BeanUtils.isNotNull(cells), "请添加货柜商品信息");
        int count = cells.size();
        Integer nums = containerType.getNums();
        logs.info("【货柜信息】货柜格子数:{},外形数量:{}", count, nums);
        Assert.isTrue(Objects.equals(nums, count), "货柜商品请补充完整");
        cabinet.setNums(nums);

        Long templateId = cabinet.getTemplateId();
        logs.info("【货柜信息】货柜模板信息{}", templateId);
        if (BeanUtils.isNull(templateId)) {
            return;
        }

        CabinetTemplateBO template = templateService.select(templateId);
        Assert.isTrue(BeanUtils.isNotNull(template), "未找到模板信息");
        cabinet.setTemplateName(template.getCabinetTemplate().getTemplateName());
    }

    /**
     * @Title create
     * @Desc 新增货柜
     * @Date 2024-04-08 16:52:16
     * @Param container 货柜信息
     */
    @Transactional
    public Long create(CabinetDTO cabinet) {
        logs.info("【新增货柜】货柜信息【{}】", cabinet);
        // 预处理货柜信息
        preHandleCabinet(cabinet);

        // 获取经理用户信息
        Long siteId = cabinet.getSiteId();
        logs.info("【新增货柜】网点ID【{}】", siteId);
        SiteDO site = BaseCache.getSite(siteId);
        Assert.isTrue(BeanUtils.isNotNull(site), "未找到网点信息");

        Assert.isTrue(BeanUtils.isNotNull(siteId), "找不到经理用户信息");

        String chipIMEI = cabinet.getChipImei();
        CabinetCheckBO params = new CabinetCheckBO();
        params.setChipImei(chipIMEI);
        // 判断芯片是否被占用
        Assert.isTrue(cabinetService.checkCabinet(params), "货柜芯片已存在");
        // 随机生成qrcode
        cabinet.setQrCode(RandomUtils.nextCode());
        cabinet.setSiteId(siteId);

        ContainerDO create = new ContainerDO();
        BeanUtils.clone(cabinet, create);
        Assert.isTrue(cabinetService.create(create), "添加失败");
        Long containerId = cabinet.getContainerId();
        logs.info("【新增货柜】货柜ID【{}】", containerId);

        // 新增网点信息
        CabinetSiteDO cabinetSite = new CabinetSiteDO();
        cabinetSite.setManagerId(siteId);
        cabinetSite.setSiteId(siteId);
        cabinetSite.setContainerId(containerId);
        Assert.isTrue(cabinetSiteService.create(cabinetSite), "添加失败");

        // 处理货柜格子信息
        List<ContainerCell> cells = cabinet.getCells();
        for (ContainerCell cell : cells) {
            cell.setContainerId(containerId);
            cellService.create(cell);
        }

        return containerId;
    }

    /**
     * @Title update
     * @Desc 修改货柜
     * @Date 2024-04-08 16:55:09
     * @Param cabinet 货柜信息
     */
    @Transactional
    public void update(CabinetDTO cabinet) {
        logs.info("【修改货柜】更新信息{}", cabinet);

        Long cabinetId = cabinet.getContainerId();
        logs.info("【修改货柜】货柜ID:{}", cabinetId);

        CabinetBO bo = cabinetService.select(cabinetId);
        logs.info("【修改货柜】原始信息:{}", bo);
        Assert.isTrue(BeanUtils.isNotNull(bo), "未找到货柜信息");

        // 预处理货柜信息
        preHandleCabinet(cabinet);

        String chipIMEI = cabinet.getChipImei();
        CabinetCheckBO params = new CabinetCheckBO();
        params.setChipImei(chipIMEI);
        params.setContainerId(cabinetId);
        Assert.isTrue(cabinetService.checkCabinet(params), "货柜芯片已存在");

        // 处理网点信息
        CabinetSiteDO site = new CabinetSiteDO();
        site.setSiteId(cabinet.getSiteId());
        site.setContainerId(cabinetId);
        Assert.isTrue(cabinetSiteService.deleteByContainerIds(cabinetId), "修改失败");
        Assert.isTrue(cabinetSiteService.create(site), "创建网点售卖柜关系失败");

        //查询货柜修改前格子信息
        List<ContainerCell> cells = cabinet.getCells();
        logs.info("【修改货柜】现在格子长度【{}】", cells.size());
        // 处理货柜格子信息
        Assert.isTrue(cellService.deleteByContainerIds(cabinetId), "修改失败");

        List<ContainerCell> cellList = new ArrayList<>();
        List<StockDO> stockList = new ArrayList<>();
        List<Integer> ordinals = new ArrayList<>();
        CellProductBO cellProductBO = new CellProductBO();
        cellProductBO.setCabinetBO(bo);
        cellProductBO.setNewCells(cells);
        cellProductBO.setCellList(cellList);
        cellProductBO.setStockList(stockList);
        cellProductBO.setOrdinals(ordinals);
        handleStock(cellProductBO);

//        if (!ordinals.isEmpty()) {
////            sendMessage(bo.getCabinet(), cellList, ordinals);
////        }

        // 跟新库存
        updateStock(stockList, cabinet.getBelongId());

        // 新增格子
        for (ContainerCell cabinetCell : cellList) {
            Assert.isTrue(cellService.create(cabinetCell), "新增失败");
        }

        ContainerDO update = new ContainerDO();
        BeanUtils.clone(cabinet, update);
        Assert.isTrue(cabinetService.update(update), "修改失败");
    }

    /**
     * @Title delete
     * @Desc 删除货柜信息
     * @Date 2024-04-08 18:11:15
     * @Param ids 货柜ID集合
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long... ids) {
        // 删除货柜 解除占用库存
        List<StockDO> stockList = new ArrayList<>();

        for (Long id : ids) {
            CabinetBO bo = cabinetService.select(id);
            List<ContainerCell> cells = bo.getCellList();
            if (BeanUtils.isNull(cells)) {
                continue;
            }

            Long belongId = bo.getCabinet().getBelongId();
            Assert.isTrue(BeanUtils.isNotNull(belongId), ErrorEnum.BUSINESS_121005.getText());

            for (ContainerCell cell : cells) {

                Integer status = cell.getStatus();
                if (Objects.equals(CellStatus.ENABLE.getCode(), status)) {
                    StockDO stock = new StockDO();
                    stock.setUsableStock(DecimalUtils.getOne());
                    stock.setFrozenStock(DecimalUtils.getOne().negate());
                    stock.setBelongId(belongId);
                    stock.setProductId(cell.getProductId());
                    stock.setDisableStock(BigDecimal.ZERO);
                    stock.setAllStock(BigDecimal.ZERO);
                    stockList.add(stock);
                }
            }

            updateStock(stockList, bo.getCabinet().getBelongId());

            AgentDTO agentDTO = cabinetConsumer.selectAgent(bo.getCabinet().getAgentId());
            Assert.isTrue(BeanUtils.isNotNull(agentDTO), "未找到代理信息");
//            cabinetConsumer.deleteUserToken(agentDTO.getBelongId());
//            cabinetConsumer.deleteUserToken(belongId);
            cabinetConsumer.deleteStaffTokeByBelongId(belongId);
        }
        Assert.isTrue(BeanUtils.isNotNull(ids), "删除失败,ids为null");
        // 移除货柜商品
        cellService.deleteByContainerIds(ids);
        // 移除货柜站点
        cabinetSiteService.deleteByContainerIds(ids);
        // 删除不解除站点 商品绑定关系
        cabinetService.delete(ids);

        cellService.deleteByContainerIds(ids);

    }


    /**
     * @param dto
     * @Title batchSetProduct
     * @Desc 批量设置商品
     * @Date 2024-09-07 10:37:43.985
     */
    @Transactional
    public void batchSetProduct(SetProductDTO dto) {
        LoginInfo user = tokenService.getUser();
        Long belongId = user.getBelongId();
        String userType = user.getUserType();

        Long siteId = dto.getSiteId();
        if (Objects.equals(UserType.SITE.getCode(), userType)) {
            BelongDO belong = BaseCache.getBelong(belongId);
            siteId = belong.getSiteId();
        } else {
            Assert.isTrue(BeanUtils.isNotNull(siteId), "请上传站点ID");
        }

        Long[] containerIds = dto.getContainerIds();
        Long templateId = dto.getTemplateId();
        List<ContainerCell> cells = dto.getCells();
        logs.info("【批量设置商品】站点ID:{}", siteId);
        logs.info("【批量设置商品】货柜Ids:{}", containerIds);
        logs.info("【批量设置商品】模板ID：{}", templateId);
        logs.info("【批量设置商品】格子信息:{}", cells);
        Assert.isTrue(BeanUtils.isNotNull(containerIds), "请上传货柜ID");
        Assert.isTrue(BeanUtils.isNotNull(templateId), "请上传模板ID");
        Assert.isTrue(BeanUtils.isNotNull(cells), "请上传商品信息");

        // 检验商品授权
        List<Long> productIds = cells.stream().map(ContainerCell::getProductId).collect(Collectors.toList());
        for (Long productId : productIds) {
            ProductAgentDO select = productAgentService.select(ProductAgentSelectQueryBO.builder().productId(productId)
                    .status(LogicCode.NO).mangerId(siteId).build());
            Assert.isTrue(BeanUtils.isNotNull(select), "缺少商品授权");
        }

        List<ContainerDO> cabinetList = new ArrayList<>();
        List<ContainerCell> cellList = new ArrayList<>();
        List<StockDO> stockList = new ArrayList<>();

        for (Long containerId : containerIds) {
            CabinetBO bo = cabinetService.select(containerId);

            List<Integer> ordinals = new ArrayList<>();
            CellProductBO cellProductDTO = new CellProductBO();
            cellProductDTO.setCabinetBO(bo);
            cellProductDTO.setNewCells(cells);
            cellProductDTO.setCellList(cellList);
            cellProductDTO.setStockList(stockList);
            cellProductDTO.setOrdinals(ordinals);
            handleStock(cellProductDTO);

            ContainerDO update = new ContainerDO();
            update.setContainerId(containerId);
            update.setTemplateId(templateId);
            cabinetList.add(update);

//            if (!ordinals.isEmpty()) {
//                sendMessage(bo.getCabinet(), cellList, ordinals);
//            }

            // 跟新库存
            updateStock(stockList, bo.getCabinet().getBelongId());
        }


        // 跟新货柜
        for (ContainerDO cabinet : cabinetList) {
            Assert.isTrue(cabinetService.update(cabinet), "修改失败");
        }

        // 删除格子
        Assert.isTrue(cellService.deleteByContainerIds(containerIds), "删除失败");

        // 新增格子
        for (ContainerCell cabinetCell : cellList) {
            Assert.isTrue(cellService.create(cabinetCell), "新增失败");
        }

    }

    /**
     * @param dto 更改参数
     * @Title handleStock
     * @Desc 处理模板之间商品库存改动信息
     * @Date 2024-09-25 15:06:52.141
     */
    public void handleStock(CellProductBO dto) {
        ContainerDO cabinet = dto.getCabinetBO().getCabinet();
        List<ContainerCell> cells = dto.getNewCells();
        List<ContainerCell> cellList = dto.getCellList();
        List<ContainerCell> originCells = dto.getCabinetBO().getCellList();
        List<StockDO> stockList = dto.getStockList();
        List<Integer> ordinals = dto.getOrdinals();
        Long containerId = cabinet.getContainerId();
        Long belongId = cabinet.getBelongId();

        for (ContainerCell cell : cells) {
            // 同一个商品商品库存不变 非同一个商品 则需要扣减原商品占用库存 提示缺货
            ContainerCell create = new ContainerCell();
            BeanUtils.clone(cell, create);
            create.setContainerId(containerId);
            if (BeanUtils.isNotNull(containerId) && originCells.size() >= cell.getOrdinal()) {
                ContainerCell ordinalCell = originCells.get(cell.getOrdinal() - 1);
                Integer status = ordinalCell.getStatus();
                Integer lackStatus = ordinalCell.getLackStatus();
                Date updateStatusTime = ordinalCell.getStatusUpdateTime();
                Date lackTime = ordinalCell.getLackTime();
                if (Objects.equals(CellStatus.ENABLE.getCode(), status) && !Objects.equals(cell.getProductId(), ordinalCell.getProductId())) {
                    StockDO stock = new StockDO();
                    stock.setUsableStock(DecimalUtils.getOne());
                    stock.setFrozenStock(DecimalUtils.getOne().negate());
                    stock.setBelongId(belongId);
                    stock.setProductId(ordinalCell.getProductId());
                    stock.setAllStock(BigDecimal.ZERO);
                    stock.setDisableStock(BigDecimal.ZERO);
                    stockList.add(stock);
                    status = CellStatus.UNABLE.getCode();
                    lackStatus = LackStatus.YES.getCode();
                    updateStatusTime = TimeUtils.getNowDate();
                    lackTime = TimeUtils.getNowDate();
                    ordinals.add(cell.getOrdinal());
                }
                create.setStatus(status);
                create.setLackStatus(lackStatus);
                create.setStatusUpdateTime(updateStatusTime);
                create.setLackTime(lackTime);
                //create.setUnlock(originCells.get(cell.getOrdinal() - 1).getUnlock());
                create.setCeilingQuantity(CabinetCalculate.getCapacityCeiling(new CapacityCeilingBO(cabinet.getTypeCode(),cell.getProductId())).intValue());
            }
            cellList.add(create);
        }
    }

    /**
     * @param list 库存列表
     * @Title updateStock
     * @Desc 修改货柜商品库存
     * @Date 2024-09-25 15:31:25.771
     */
    private void updateStock(List<StockDO> list, Long belongId) {
        Integer stockStatus = cabinetConsumer.getStockStatus(belongId);

        if (Objects.equals(LogicCode.YES, stockStatus)) {
            cabinetConsumer.handleStock(list);
        }
    }


    public Integer updateCabinetCell(Integer productNums, Integer ordinal, Long containerId, Integer action /*0-补货 1-订单*/) {
        ContainerCell cell = cellService.select(CabinetCellSelectQueryBO.builder().cabinetId(containerId).ordinal(ordinal).build());
        Integer allNums = productNums;
        if (action == 1) {
            // 校验是否超出
            allNums = CapacityValidate.checkQuantity(cell.getProductQuantity(), productNums, CapacityOperateEnum.SUBTRACT.getCode()) ? cell.getProductQuantity() - productNums : 0;
        } else {
            allNums = cell.getProductQuantity() + productNums;
            allNums = CapacityValidate.checkQuantity(cell.getCeilingQuantity(), allNums, CapacityOperateEnum.SUBTRACT.getCode()) ? allNums : cell.getCeilingQuantity();
        }
        CabinetCellUpdateBO update = new CabinetCellUpdateBO();
        update.setCellId(cell.getCellId());
        update.setProductQuantity(allNums);
        update.setLackStatus(CabinetCalculate.getLackStatus(allNums));
        update.setStatus(CabinetCalculate.getCabinetCellStatus(allNums));
        if (!cell.getStatus().equals(update.getStatus())) {
            update.setStatusUpdateTime(TimeUtils.getNowDate());
            if (CellStatus.UNABLE.getCode().equals(update.getStatus())) {
                GuavaEventBus.post(new NoCargoNoticeEvent(new LoginInfo(), containerId));
            }
        }
        if (!cell.getLackStatus().equals(update.getLackStatus())) {
            update.setLackTime(TimeUtils.getNowDate());
            if (LackStatus.YES.getCode().equals(update.getLackStatus())) {
                GuavaEventBus.post(new LackCargoNoticeEvent(new LoginInfo(), containerId));
            }
        }
        Assert.isTrue(cellService.update(update), "货柜格子处理失败");
        return allNums;
    }

    public void resetCabinetCell(OrderDO orderDO, Integer ordinal) {
        ContainerCell cell = cellService.select(CabinetCellSelectQueryBO.builder().cabinetId(orderDO.getContainerId()).ordinal(ordinal).build());
        Integer stockStatus = cabinetConsumer.getStockStatus(orderDO.getBelongId());
        List<StockDO> stockList = new ArrayList<>();
        if (Objects.equals(LogicCode.YES, stockStatus)) {
            StockDO stock = new StockDO();
            stock.setBelongId(orderDO.getBelongId());
            stock.setProductId(cell.getProductId());
            stock.setAllStock(BigDecimal.ZERO);
            stock.setFrozenStock(BigDecimal.valueOf(orderDO.getProductNums()).negate());
            stock.setUsableStock(BigDecimal.valueOf(orderDO.getProductNums()));
            stock.setDisableStock(BigDecimal.ZERO);
            stockList.add(stock);
            cabinetConsumer.handleStock(stockList);
        }
        // 修改格子状态
        CabinetCellUpdateBO update = new CabinetCellUpdateBO();
        update.setCellId(cell.getCellId());
        update.setProductQuantity(0);
        update.setStatus(CellStatus.UNABLE.getCode());
        update.setLackStatus(LackStatus.YES.getCode());
        if (!cell.getStatus().equals(update.getStatus())) {
            update.setStatusUpdateTime(TimeUtils.getNowDate());
        }
        if (!cell.getLackStatus().equals(update.getLackStatus())) {
            update.setLackTime(TimeUtils.getNowDate());
        }
        Assert.isTrue(cellService.update(update), "货柜格子处理失败");

    }

    /**
     * @Title unbindCabinet
     * @Desc 解绑货柜
     * @Date 2024-10-24 13:53:09.868
     */
    @Transactional
    public void unbindCabinet(Long containerId) {

        CabinetBO bo = cabinetService.select(containerId);
        ContainerDO cabinet = bo.getCabinet();
        Long belongId = cabinet.getBelongId();
        Assert.isTrue(BeanUtils.isNotNull(belongId), "当前货柜不可进行解绑操作");

        ContainerDO create = new ContainerDO();
        create.setContainerName("柜" + TimeUtils.dateTimeNow());
        create.setNums(cabinet.getNums());
        create.setQrcode(cabinet.getQrcode());
        create.setChipImei(cabinet.getChipImei());
        create.setChipSn(cabinet.getChipSn());
        create.setUseStatus(UseStatus.DISUSE.getCode());
        create.setTypeCode(cabinet.getTypeCode());
        cabinet.setDelFlag(LogicCode.NO);

        // 货柜库存 未作处理 库存改为单个处理再做处理
        Integer stockStatus = cabinetConsumer.getStockStatus(belongId);
        if (Objects.equals(LogicCode.YES, stockStatus)) {
            List<ContainerCell> cells = bo.getCellList();
            List<StockDO> stockList = new ArrayList<>();
            for (ContainerCell cell : cells) {
                StockDO stock = new StockDO();
                if (Objects.equals(CellStatus.ENABLE.getCode(), cell.getStatus())) {
                    stock.setBelongId(belongId);
                    stock.setProductId(cell.getProductId());
                    stock.setAllStock(BigDecimal.ZERO);
                    stock.setFrozenStock(BigDecimal.ONE.negate());
                    stock.setUsableStock(BigDecimal.ONE);
                    stock.setDisableStock(BigDecimal.ZERO);
                    stockList.add(stock);
                }
            }
            cabinetConsumer.handleStock(stockList);
        }

        // 删除token
        AgentDTO agentDTO = cabinetConsumer.selectAgent(cabinet.getAgentId());
        Assert.isTrue(BeanUtils.isNotNull(agentDTO), "未找到代理信息");
//        cabinetConsumer.deleteUserToken(agentDTO.getBelongId());
//        cabinetConsumer.deleteUserToken(belongId);
        cabinetConsumer.deleteStaffTokeByBelongId(belongId);

        Assert.isTrue(cabinetService.delete(containerId), "删除失败");

        Assert.isTrue(cabinetSiteService.deleteByContainerIds(containerId), "修改失败");

        Assert.isTrue(cabinetService.create(create), "新增失败");

        Assert.isTrue(cellService.deleteByContainerIds(containerId), "删除失败");


    }

    /*------------------------------------------ 搜索栏 ------------------------------------------*/

    /**
     * @param name 货柜名称
     * @Title searchName
     * @Desc 货柜名称匹配搜索
     * @Date 2024-08-29 14:01:02.250
     * @Return List<String> 名称匹配结果
     */
    public List<String> searchName(String name) {
        Assert.isTrue((name.length() <= 15), "输入的货柜名称不合规");
        StorageFiledDTO param = new StorageFiledDTO();
        param.setContainerName(name);
        param.setSearchFiled("c.container_name");
        handleParam(param);
        List<String> list = cabinetService.searchTableField(param);
        return BeanUtils.isNotNull(list) ? list : new ArrayList<>();
    }

    /**
     * @param siteName 网点名称
     * @Title searchSiteName
     * @Desc 网点名称匹配
     * @Date 2024-08-29 14:01:39.781
     * @Return List<String> 名称匹配结果
     */
    public List<String> searchSiteName(String siteName) {
        Assert.isTrue((siteName.length() <= 15), "输入的网点名称不合规");
        StorageFiledDTO param = new StorageFiledDTO();
        param.setSiteName(siteName);
        param.setSearchFiled("ts.site_name");
        handleParam(param);
        List<String> list = cabinetService.searchTableField(param);
        return BeanUtils.isNotNull(list) ? list : Collections.emptyList();
    }

    /**
     * @param agentName 代理名称
     * @Title searchAgentName
     * @Desc 代理名称匹配
     * @Date 2024-08-29 14:02:12.997
     * @Return List<String> 名称匹配结果
     */
    public List<String> searchAgentName(String agentName) {
        Assert.isTrue((agentName.length() <= 15), "输入的代理商名称不合规");
        StorageFiledDTO param = new StorageFiledDTO();
        param.setAgentName(agentName);
        param.setSearchFiled("au.agent_name");
        handleParam(param);
        List<String> list = cabinetService.searchTableField(param);
        return BeanUtils.isNotNull(list) ? list : Collections.emptyList();
    }

    public List<CabinetCycleVO> cyclePageList(CabinetCycleDTO dto) {
        return containerCycleService.cyclePageList(dto);
    }


    public boolean createScanMsg(CabinetScanCreateDTO dto) {
        String scanCode = dto.getScanCode();
        String lockCode = LockCacheConstant.CABINET_SCAN_MSG_LOCK + scanCode;
        try {
            boolean b = LockUtil.tryLock(lockCode, 20, 60);
            if (b) {
                ContainerScanDO scanMsg = cabinetService.getScanMsg(scanCode);
                LoginInfo wechatUser = Optional.ofNullable(SystemContext.getUser()).orElseGet(() -> {
                    LoginInfo loginInfo = new LoginInfo();
                    loginInfo.setUserId(-1L);
                    loginInfo.setPhone("-");
                    loginInfo.setNickname("游客");
                    return loginInfo;
                });
                ContainerDO byQrcode = cabinetService.getByQrcode(dto.getQrCode());
                Assert.isTrue(byQrcode != null, "没有找到货柜" + byQrcode);
                if (scanMsg == null) {
                    scanMsg = new ContainerScanDO(scanCode, wechatUser.getUserId(), wechatUser.getPhone(), wechatUser.getNickname(),
                            byQrcode.getContainerId(), 0, 0);
                } else {
                    BeanUtils.copyExcludeBase(dto, scanMsg);
                }
                if (CabinetScanActionEnums.ORDER.getCode().equals(dto.getActionType()))
                    scanMsg.setOrderTimes(scanMsg.getOrderTimes() + 1);
                else if (CabinetScanActionEnums.QUERY_PRODUCT.getCode().equals(dto.getActionType()))
                    scanMsg.setQueryProductTimes(scanMsg.getQueryProductTimes() + 1);
                cabinetService.saveOrUpdateScanMsg(scanMsg);
                dto.setScanCode(scanCode);
            }
        } finally {
            LockUtil.unlock(lockCode);
        }
        return true;
    }

    public List<SpecificUpgradeCabinetVO> specificUpgradeList(SpecificUpgradeCabinetParam param) {
        return cabinetService.specificUpgradeCabinetVOList(param);
    }

    public void deleteByCode(String code) {
        CabinetBO bo = cabinetService.select(CabinetSelectQueryBo.builder().qrcode(code).build());
        delete(bo.getCabinet().getContainerId());
    }

    public Integer getCapacityCeiling(CapacityCeilingDTO dto) {
        return DeviceStrategyFactory.getStrategy(dto.getTypeCode()).getProductCeiling(dto.getTypeCode(), dto.getProductId());
    }

    public void changeProduct(SetProductDTO dto) {
        String qrcode = dto.getQrcode();
        CabinetBO cabinetBO = cabinetService.select(CabinetSelectQueryBo.builder().qrcode(qrcode).build());
        Assert.isTrue(BeanUtils.isNotNull(cabinetBO), ErrorEnum.BUSINESS_712001.getText());

        ContainerDO cabinet = cabinetBO.getCabinet();
        List<ContainerCell> cellList = cabinetBO.getCellList();
        Long belongId = cabinet.getBelongId();

        // 剔除库存
        List<StorageProductDTO> detailList = new ArrayList<>();
        for (ContainerCell cell : cellList) {
            StorageProductDTO stockDO = new StorageProductDTO();
            stockDO.setProductId(cell.getProductId());
            stockDO.setFrozenStock(BigDecimal.valueOf(cell.getProductQuantity()).negate());
            stockDO.setUsableStock(BigDecimal.valueOf(cell.getProductQuantity()));
            detailList.add(stockDO);
        }
        SpringEventBus.getInstance().publish(new EventData<>(new StorageQuantityEvent(belongId, detailList)));
        // 删除格子
        cellService.deleteByContainerIds(cabinet.getContainerId());
        Long productId = dto.getProductId();
        ContainerCell cell = new ContainerCell();
        cell.setProductId(productId);
        cell.setOrdinal(1);
        cell.setLackStatus(LackStatus.YES.getCode());
        cell.setLackTime(TimeUtils.getNowDate());
        cell.setStatus(CellStatus.UNABLE.getCode());
        cell.setContainerId(cabinet.getContainerId());
        CapacityCeilingBO ceilingBO = new CapacityCeilingBO();
        ceilingBO.setProductId(productId);
        ceilingBO.setTypeCode(cabinet.getTypeCode());
        cell.setCeilingQuantity(CabinetCalculate.getCapacityCeiling(ceilingBO).intValue());
        cellService.create(cell);
    }

    public List<CabinetCargoInfoDTO> monitorQuantity(String maintainCode, String imei) {
        String typeCode = CabinetCache.getTypeCode(imei);
        ICommonDeviceInfo afterDeviceInfo = DeviceSpinService.spinGet(imei, Objects::nonNull, ContainerTypeEnum.getClass(typeCode));
        CommonDeviceInfoBO commonDeviceInfoBO = deviceService.getDeviceInfoBO(maintainCode);
        if (BeanUtils.isNull(commonDeviceInfoBO)) {
            return new ArrayList<>();
        }
        ICommonDeviceInfo beforeDeviceInfo = commonDeviceInfoBO.getBeforeDeviceInfo();
        Assert.isTrue(DeviceStrategyFactory.getStrategy(typeCode).isLock(beforeDeviceInfo.getImei()), "补货舱门未关闭");
        List<CabinetCargoInfoDTO> infoDTOList = new ArrayList<>();
        CabinetCacheDTO cabinet = CabinetCache.getCabinet(beforeDeviceInfo.getImei());
        List<ContainerCell> cellList = CabinetCache.getCellList(cabinet.getContainerId());
        Map<Integer, DeviceCellDetailDTO> afterMap = ConvertDataUtil.list2KeyValueMap(afterDeviceInfo.getDetailList(), ICommonDeviceDetail::getOrdinal, ICommonDeviceDetail::getCellDetail);
        Map<Integer, DeviceCellDetailDTO> beforeMap = ConvertDataUtil.list2KeyValueMap(beforeDeviceInfo.getDetailList(), ICommonDeviceDetail::getOrdinal, ICommonDeviceDetail::getCellDetail);
        Map<Integer, Integer> afterDistance = ConvertDataUtil.list2KeyValueMap(afterDeviceInfo.getDetailList(), ICommonDeviceDetail::getOrdinal, ICommonDeviceDetail::getDistance);
        for (ContainerCell cell : cellList) {
            Integer ordinal = cell.getOrdinal();
            infoDTOList.add(new CabinetCargoInfoDTO(
                    ordinal, cell.getProductId(),
                    afterMap.get(ordinal).getProductNums() - beforeMap.get(ordinal).getProductNums(),
                    cell.getCeilingQuantity()-Objects.requireNonNull(CabinetCalculate.getEventQuantity(imei,
                            CabinetCache.getContainerType(cabinet.getTypeCode()).getTypeHeight().intValue()
                                    - afterDistance.get(ordinal), ordinal), "找不到格子").getProductNums()));
        }
        deviceService.updateEvent(maintainCode, String.valueOf(afterDeviceInfo));
        return infoDTOList;
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void handleTissueCell(Long belongId, ContainerCell cell) {
        CabinetCellUpdateBO cabinetCellUpdateBO = getCabinetCellUpdateBO(cell);
        cellService.update(cabinetCellUpdateBO);
        Integer stockStatus = cabinetConsumer.getStockStatus(belongId);
        if (Objects.equals(LogicCode.YES, stockStatus) && (cell.getProductQuantity() != cabinetCellUpdateBO.getProductQuantity())) {
            List<StockDO> list = new ArrayList<>();
            StockDO stockDO = new StockDO();
            stockDO.setBelongId(belongId);
            stockDO.setProductId(cell.getProductId());
            stockDO.setFrozenStock(BigDecimal.valueOf(cell.getProductQuantity()).negate());
            stockDO.setUsableStock(BigDecimal.valueOf(cell.getProductQuantity()));
            stockDO.setAllStock(BigDecimal.ZERO);
            stockDO.setDisableStock(BigDecimal.ZERO);
            list.add(stockDO);
            cabinetConsumer.handleStock(list);
        }
    }

    private static CabinetCellUpdateBO getCabinetCellUpdateBO(ContainerCell cell) {
        CabinetCellUpdateBO update = new CabinetCellUpdateBO();
        update.setCellId(cell.getCellId());
        if (!CellStatus.UNABLE.getCode().equals(cell.getStatus())) {
            update.setStatus(CellStatus.UNABLE.getCode());
            update.setStatusUpdateTime(TimeUtils.getNowDate());
        }
        if (!LackStatus.YES.getCode().equals(cell.getLackStatus())) {
            update.setLackStatus(LackStatus.YES.getCode());
            update.setStatusUpdateTime(TimeUtils.getNowDate());
        }
        update.setProductQuantity(0);
        return update;
    }

    public boolean checkVolt(String qrcode) {
        ContainerDO cabinet = cabinetService.getByQrcode(qrcode);
        return DeviceCommandEngine.isVolt(cabinet.getChipImei());
    }

    public ContainerProductVO getContainerProductByImei(String imei) {
        Map<Integer, DeviceCellDetailDTO> numMap = CabinetCalculate.getNumMap(imei);
        ContainerProductVO vo = new ContainerProductVO();
        ContainerPriceBO cabinetPrice = CabinetCache.getCabinetPrice(imei);
        Map<String, ContainerProductDetailVO> productMap = Maps.newHashMap();
        List<ContainerCellPriceBO> cellPriceList = cabinetPrice.getCellPriceList();
        for (ContainerCellPriceBO cellPriceBO : cellPriceList) {
            String sku = cellPriceBO.getProductBelong().getProductDTO().getSku();
            Integer ordinal = cellPriceBO.getCell().getOrdinal();
            ContainerProductDetailVO detailVO = productMap.get(sku);
            if (detailVO == null)
                detailVO = CabinetConvert.priceCellBO2VO(cellPriceBO);
            Integer num = Optional.ofNullable(numMap.get(ordinal)).map(DeviceCellDetailDTO::getProductNums)
                    .orElse(0);
            // 如果通道的商品数量大于1 就减去1 如果=1就不减
            num = num > 1 ? num - 1 : num;
            detailVO.setMaxSaleNums(detailVO.getMaxSaleNums() + num);
            productMap.put(sku, detailVO);
        }
        CabinetCacheDTO container = cabinetPrice.getContainer();
        BeanUtils.clone(container, vo);
        vo.setProductList(new ArrayList<>(productMap.values()));
        return vo;
    }

    public ContainerProductVO getContainerProductByQr(String qrcode) {
        return getContainerProductByImei(cabinetService.getImeiByQrcode(qrcode));
    }

    public String getImeiByQrcode(String qrcode) {
        return cabinetService.getImeiByQrcode(qrcode);
    }
}



